﻿//================================================================================
// Filename: PluginManager.as
// Authour: Jacky Fong
// Description:
// Managing plugins and provide a transparent layer for the communications between
// plugins
//
// API
// - apiLog
// - apiAddChild
// - apiSwapChildren
// - apiSetChildIndex
// - apiGetNumChildren
//
// Input Events
// - KeyboardEvent.KEY_DOWN
//
// Output Events
// - LoadPluginComplete
// - LoadPluginsComplete
// - LoadPluginsPriority0Complete
// - KeyboardEvent.KEY_DOWN
//================================================================================

package
{
	import flash.display.DisplayObjectContainer;
	import flash.display.DisplayObject;
    import flash.display.Loader;
	import flash.display.Stage;
    import flash.net.URLRequest;
	import flash.net.URLLoader;
    import flash.events.*;
	import IPlugin;
	import PluginEvent;

	public class PluginManager extends EventDispatcher
	{
		private var _main:DisplayObjectContainer;
		private var _pluginList:Object;
		private var _loadingQueue:Object;
		
		public function PluginManager( main:DisplayObjectContainer )
		{
			_main = main;
			_init();
		}

		private function _init():void
		{
			_pluginList = new Object();
			_loadingQueue = new Object();
			_setupEventListeners();		
		}
		
		private function _setupEventListeners():void
		{
			// listen to main's keyboard events
			_main.stage.addEventListener( KeyboardEvent.KEY_DOWN, _onKeyDown );			
		}
		
		private function _onKeyDown( evt:KeyboardEvent ):void
		{
			dispatchEvent( evt );
		}
		
		//==========================================================================
		// load plugins
		//==========================================================================
		public function loadPlugin( url:String, priority:uint ):void
		{
			var pm:PluginManager = this;
			var func:Object = new Object();		
			func.loadPluginComplete = function( evt:Event )
			{
				var pi:IPlugin = evt.target.content;
				pi.setManager( pm );
				_pluginList[ pi.pluginName ] = pi;
				trace( pm + " Load Plugin " + pi + " Complete" );
				dispatchEvent( new PluginEvent( "LoadPluginComplete", { plugin:url , priority:_loadingQueue[ url ].priority } ) );				
				delete _loadingQueue[ url ];				
				
				var count:uint = 0;
				for( var p in _loadingQueue ) {
					if( _loadingQueue[ p ].priority != priority ) continue;
					count++;
				}
				if( count == 0 ) {
					dispatchEvent( new PluginEvent( "LoadPluginsComplete", { priority:priority } ) );
				}
			}
			
			func.loadPluginIoError = function( evt:IOErrorEvent )
			{
				trace( pm + " Load Plugin IoError: " + evt );
			}
			
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener( Event.COMPLETE, func.loadPluginComplete );			
			loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, func.loadPluginIoError );
			var req:URLRequest = new URLRequest( url );
			loader.load( req );
		}
		
/*		
		// todo: from a directory containing plugins	
		public function loadPluginsFromPath( path:String ):void
		{
			// test
			loadPlugin( "LoggerPlugin.swf" );
			loadPlugin( "PagePlugin.swf" );
			loadPlugin( "NavigationBarPlugin.swf" );			
		}
*/		
		public function loadXML( url:String ):void
		{		
			var loader:URLLoader = new URLLoader();
			var req:URLRequest = new URLRequest( url );
			loader.load( req );
			loader.addEventListener( Event.COMPLETE, _loadXMLComplete );
			loader.addEventListener( IOErrorEvent.IO_ERROR, _loadXMLIoError );
		}
		
		private function _loadXMLComplete( evt:Event ):void
		{
			trace( this + " Load XML Complete: " + evt );
			var xml:XML = new XML( evt.target.data );
			for each( var plugin:XML in xml..plugin ) {
				_loadingQueue[ plugin.attribute( "url" ) ] = { priority:plugin.attribute( "priority" ) };
			}			
			dispatchEvent( new Event( "LoadPluginXMLComplete" ) );			
		}

		private function _loadXMLIoError( evt:IOErrorEvent ):void
		{
			trace( this + " Load XML IoError: " + evt );
		}
		
		public function loadPlugins( priority:uint ):void
		{
			for( var p in _loadingQueue ) {
				if( _loadingQueue[ p ].priority != priority ) continue;		
				loadPlugin( p, priority );
			}			
		}
		
		//==========================================================================
		// API for plugins
		//==========================================================================
		public function apiLog( logMsg:String ):void
		{
			dispatchEvent( new PluginEvent( "API_Log", { msg:logMsg } ) );
		}
		
		public function apiAddChild( child:DisplayObject ):DisplayObject
		{
			return _main.addChild( child );
		}

		public function apiSwapChildren( child1:DisplayObject, child2:DisplayObject ):void
		{
			_main.swapChildren( child1, child2 );
		}
		
		public function apiSetChildIndex( child:DisplayObject, index:int ):void
		{
			_main.setChildIndex( child, index );
		}
		
		public function apiGetNumChildren():int
		{
			return _main.numChildren;
		}
		
		public function apiGetStage():Stage
		{
			return _main.stage;
		}
	}
}